#include "fibevent.h"
#include "IocpServerSocket.h"
#include "wxtl/Fiber.h"

IocpServerSocket::IocpServerSocket( wxtl::Socket& soket ) :m_socket(soket)
{
	wprintf(L"New IocpServerSocket for %s:%i\n", m_socket.getRemoteAddr().getDottedAddr().c_str(), m_socket.getRemoteAddr().getPort());
}

void IocpServerSocket::Close()
{
	m_socket.close();
}

bool IocpServerSocket::IsConnected()
{
	return m_socket.IsConnected();
}

IocpServerSocket::~IocpServerSocket()
{
	printf("IocpServerSocket destroyed\n");
}

bool IocpServerSocket::ProcessIocpRequest()
{
	
	if(!m_socket.isValid())
	{
		//must find better case here
		SetResult(IocpResult(0,wxtl::_win32_error(S_OK), true));
	}

	try
	{
		bool ret = false;
		switch((int)m_request.m_type)
		{
			case IocpIoRequest::None:
			{
				abort();
				return false;
			}

			case IocpIoRequest::TransmitFile:
			{
				TRANSMIT_FILE_BUFFERS buffers = {0};
				if(m_request.m_head)
				{
					buffers.Head = m_request.m_head->pointer;
					buffers.HeadLength = m_request.m_head->size;
				}
				if(m_request.m_tail)
				{
					buffers.Tail = m_request.m_tail->pointer;
					buffers.TailLength = m_request.m_tail->size;
				}
				m_socket.TransmitFile(*m_request.m_file, m_request.m_dataSize, 0, (LPOVERLAPPED)m_request.m_operation, &buffers, 0);
				break;
			}

			case IocpIoRequest::Read:
			{
				ret = m_socket.recv(m_request.m_data,m_request.m_dataSize,NULL,NULL,(LPOVERLAPPED)m_request.m_operation);
				break;
			}

			case IocpIoRequest::Write:
			{
				ret = m_socket.send(m_request.m_data,m_request.m_dataSize,NULL,NULL,(LPOVERLAPPED)m_request.m_operation);
				break;
			}

			case IocpSocketConnectRequest::Connect:
			{
				m_socket.bind();
				m_socket.connect(m_requestEx.port, m_requestEx.address.c_str(), (LPOVERLAPPED)m_request.m_operation);
			}

		}
	}
	catch (const wxtl::_win32_error& e)
	{
		SetResult(IocpResult(0, e, true));
		return false; 
	}	

	return true;
}

void IocpServerSocket::Connect(const char* adr, UINT port)
{
	IocpOperation* operation = PrepareExOperation();
	m_request = IocpIoRequest(operation, (IocpIoRequest::Type) IocpSocketConnectRequest::Connect, NULL, 0);
	m_requestEx = IocpSocketConnectRequest(adr, port);

	Switch();
}


